import { FormattedKlineData } from '../services/market-data.service';
import { IStrategy, TradeOrder, TradeSignal } from './strategy.interface';
import { SimulatedAccount } from './simulated-account.service';
import { SimulatedContractAccount } from './simulated-contract-account.service';
import { formatToUTC8 } from '../utils/time.utils';

/**
 * 回测账户类型
 */
export enum AccountType {
  SPOT = 'spot',
  CONTRACT = 'contract'
}

/**
 * 回测引擎配置
 */
export interface BacktestEngineConfig {
  initialBalance: number;
  feeRate: number;
  accountType?: AccountType;
  leverage?: number;
}

/**
 * 回测引擎 (BacktestEngine)
 *
 * 这是回测框架的核心驱动器。它负责：
 * 1. 接收一个策略实例和历史K线数据。
 * 2. 根据账户类型（现货或合约）初始化一个模拟账户。
 * 3. 按时间顺序遍历每一根K线。
 * 4. 调用策略的 `update` 方法获取交易信号。
 * 5. 根据信号指令，让模拟账户执行交易。
 * 6. 在所有数据都处理完毕后，生成并打印最终的回测报告。
 */
export class BacktestEngine {
  private readonly historicalData: FormattedKlineData[];
  private readonly strategy: IStrategy;
  private readonly account: SimulatedAccount | SimulatedContractAccount;
  private readonly accountType: AccountType;

  constructor(
    strategy: IStrategy,
    historicalData: FormattedKlineData[],
    config: BacktestEngineConfig
  ) {
    this.strategy = strategy;
    this.historicalData = historicalData;
    this.accountType = config.accountType || AccountType.SPOT;

    if (this.accountType === AccountType.CONTRACT) {
      this.account = new SimulatedContractAccount(
        config.initialBalance,
        config.feeRate,
        config.leverage || 10 // 默认10倍杠杆
      );
    } else {
      this.account = new SimulatedAccount(config.initialBalance, config.feeRate);
    }
  }

  /**
   * 启动回测流程。
   */
  public run(): void {
    if (this.historicalData.length === 0) {
      console.error("Historical data is empty. Aborting backtest.");
      return;
    }

    console.log(`\nRunning backtest for strategy: "${this.strategy.name}"...`);
    console.log(`Account Type: ${this.accountType.toUpperCase()}`);
    const startTime = this.historicalData[0].timestamp;
    const endTime = this.historicalData[this.historicalData.length - 1].timestamp;
    console.log(`Data from ${formatToUTC8(new Date(startTime))} to ${formatToUTC8(new Date(endTime))}`);
    console.log(`Total K-line bars: ${this.historicalData.length}`);

    // 遍历每一根K线数据
    for (const kline of this.historicalData) {
      // 1. 让策略根据当前K线做出决策
      const signal = this.strategy.update(kline);

      // 2. 根据策略返回的信号执行交易
      this.executeTrade(signal, kline);

      // 3. 在每个K线周期结束后更新账户的未实现盈亏和回撤
      this.account.updatePnlAndDrawdown(kline);
    }

    // 4. 所有数据回测完毕，获取最后一根K线的收盘价用于计算最终资产
    const lastPrice = this.historicalData[this.historicalData.length - 1].close;
    this.account.printResults(lastPrice);
  }

  /**
   * 根据信号执行交易
   */
  private executeTrade(order: TradeOrder, kline: FormattedKlineData): void {
    // 优先使用指令中指定的价格（用于止盈/止损），否则使用当前K线的收盘价
    const tradePrice = order.price || kline.close;
    const timestamp = kline.timestamp;

    // 合约账户交易逻辑
    if (this.account instanceof SimulatedContractAccount) {
      switch (order.signal) {
        case TradeSignal.OPEN_LONG:
          this.account.openLong(tradePrice, timestamp);
          break;
        case TradeSignal.CLOSE_LONG:
          this.account.closeLong(tradePrice, timestamp);
          break;
        case TradeSignal.OPEN_SHORT:
          this.account.openShort(tradePrice, timestamp);
          break;
        case TradeSignal.CLOSE_SHORT:
          this.account.closeShort(tradePrice, timestamp);
          break;
      }
    }
    // 现货账户交易逻辑
    else if (this.account instanceof SimulatedAccount) {
      switch (order.signal) {
        case TradeSignal.BUY:
          this.account.buy(tradePrice, timestamp);
          break;
        case TradeSignal.SELL:
          this.account.sell(tradePrice, timestamp);
          break;
      }
    }
  }
}
